﻿using System;
using System.Collections.Generic;
using Gdi = System.Drawing;
using GdiImaging = System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using SysImaging = System.Windows.Media.Imaging;
using iNet.IO;

namespace iNet.Media.Imaging
{
	/// <summary>
	/// 提供影像相關功能。
	/// </summary>
	public unsafe static class ImageUtility
	{
		#region AccessPixelBuffer
		/// <summary>
		/// 存取指定點陣圖的像素緩衝區。
		/// </summary>
		/// <param name="bitmap">指定的點陣圖。</param>
		/// <param name="callback">存取像素緩衝區的回呼方法。</param>
		/// <exception cref="ArgumentNullException">bitmap 或 callback 為 Null (Visual Basic 為 Nothing)。</exception>
		public static void AccessPixelBuffer(this IBitmapImage bitmap, AccessPixelBufferCallback callback)
		{
			//確認參數
			if (bitmap == null)
				throw new ArgumentNullException("bitmap");
			if (callback == null)
				throw new ArgumentNullException("callback");

			//取得緩衝區
			bool isPixelBufferLocked = false;
			IntPtr pixelBuffer = IntPtr.Zero;
			int stride = 0;
			GCHandle? pixelBufferHandle = null;
			byte[] pixelBufferArray = null;
			if (bitmap.HasDirectPixelBuffer)
			{
				bitmap.LockPixelBuffer();
				pixelBuffer = bitmap.PixelBuffer;
				stride = bitmap.PixelBufferStride;
				isPixelBufferLocked = true;
			}
			if (pixelBuffer == IntPtr.Zero)
			{
				pixelBufferArray = CopyPixelsToByteArray(bitmap, bitmap.PixelFormat, bitmap.Palette);
				pixelBufferHandle = GCHandle.Alloc(pixelBufferArray, GCHandleType.Pinned);
				pixelBuffer = pixelBufferHandle.Value.AddrOfPinnedObject();
				stride = (pixelBufferArray.Length / bitmap.PixelHeight);
			}

			//存取點陣圖
			bool modified = false;
			try
			{
				callback(pixelBuffer, bitmap.PixelWidth, bitmap.PixelHeight, stride, bitmap.PixelFormat, bitmap.Palette, ref modified);
			}
			finally
			{
				if (pixelBufferHandle != null)
				{
					//釋放資源
					pixelBufferHandle.Value.Free();

					//寫入像素資料
					if (modified)
						bitmap.WritePixels(bitmap.PixelFormat, bitmap.Palette, pixelBufferArray);
				}
				if (isPixelBufferLocked)
					bitmap.UnlockPixelBuffer();
			}
		}
		#endregion
		#region ConvertPixelFormat
		/// <summary>
		/// 轉換點陣圖的像素格式。
		/// </summary>
		/// <param name="bitmap">指定的點陣圖。</param>
		/// <param name="pixelFormat">新的像素格式。</param>
		/// <returns>轉換後的點陣圖。</returns>
		/// <exception cref="ArgumentNullException">bitmap 為 Null (Visual Basic 為 Nothing)。</exception>
		public static IBitmapImage ConvertPixelFormat(this IBitmapImage bitmap, PixelFormat pixelFormat)
		{
			return ConvertPixelFormat(bitmap, pixelFormat, null);
		}
		/// <summary>
		/// 轉換點陣圖的像素格式或使用指定的調色盤。
		/// </summary>
		/// <param name="bitmap">指定的點陣圖。</param>
		/// <param name="pixelFormat">新的像素格式。</param>
		/// <param name="palette">新的調色盤。</param>
		/// <returns>轉換後的點陣圖。</returns>
		/// <exception cref="ArgumentNullException">bitmap 為 Null (Visual Basic 為 Nothing)。</exception>
		public static IBitmapImage ConvertPixelFormat(this IBitmapImage bitmap, PixelFormat pixelFormat, BitmapPalette palette)
		{
			//確認參數
			if (bitmap == null)
				throw new ArgumentNullException("bitmap");
			if (bitmap.PixelFormat == pixelFormat && bitmap.Palette == palette)
				return (bitmap.Clone() as IBitmapImage);

			//轉換格式
			BitmapSource bitmapSource = new FormatConvertedBitmap(bitmap.ToBitmapSource(), pixelFormat, palette, 0.5);
			return new BitmapImage(bitmap.MediaStorage, bitmapSource, bitmap.IsReadOnly, bitmap.Metadata, bitmap.RawFormat);
		}
		#endregion
		#region CopyBitmap
		/// <summary>
		/// 建立點陣圖的完全複本。
		/// </summary>
		/// <param name="bitmap">指定的點陣圖。</param>
		/// <returns>點陣圖的複本。</returns>
		/// <exception cref="ArgumentNullException">bitmap 為 Null (Visual Basic 為 Nothing)。</exception>
		public static BitmapSource CopyBitmap(BitmapSource bitmap)
		{
			//確認
			if (bitmap == null)
				throw new ArgumentNullException("bitmap");

			//複製
			return CopyBitmap(bitmap, bitmap.DpiX, bitmap.DpiY);
		}
		/// <summary>
		/// 建立點陣圖的完全複本。
		/// </summary>
		/// <param name="bitmap">指定的點陣圖。</param>
		/// <param name="dpiX">水平解析度 (DPI)。</param>
		/// <param name="dpiY">垂直解析度 (DPI)。</param>
		/// <returns>點陣圖的複本。</returns>
		/// <exception cref="ArgumentNullException">bitmap 為 Null (Visual Basic 為 Nothing)。</exception>
		public static BitmapSource CopyBitmap(BitmapSource bitmap, double dpiX, double dpiY)
		{
			//確認
			if (bitmap == null)
				throw new ArgumentNullException("bitmap");

			//取得資料
			int pixelWidth = bitmap.PixelWidth;
			int pixelHeight = bitmap.PixelHeight;
			PixelFormat pixelFormat = bitmap.Format;

			//複製像素資料
			int stride = (pixelFormat.BitsPerPixel * pixelWidth) / 8;
			int padding = 4 - (stride % 4);
			if (padding < 4)
				stride += padding;
			byte[] buffer = new byte[stride * pixelHeight];
			bitmap.CopyPixels(buffer, stride, 0);

			//回傳新點陣圖
			return SysImaging.BitmapImage.Create(pixelWidth, pixelHeight, dpiX, dpiY, pixelFormat, bitmap.Palette, buffer, stride).GetAsFrozen() as BitmapSource;
		}
		#endregion
		#region CopyPixelsToByteArray
		/// <summary>
		/// 複製指定點陣圖中的像素資料。
		/// </summary>
		/// <param name="bitmap">指定的點陣圖。</param>
		/// <param name="pixelFormat">指定的像素格式。</param>
		/// <param name="palette">指定像素格式所需的調色盤。</param>
		/// <returns>表示點陣圖像素資料的位元組陣列。</returns>
		/// <exception cref="ArgumentNullException">bitmap 為 Null (Visual Basic 為 Nothing)。</exception>
		public static byte[] CopyPixelsToByteArray(this IBitmapImage bitmap, PixelFormat pixelFormat, BitmapPalette palette)
		{
			return CopyPixelsToByteArray(bitmap, Int32Rect.Empty, pixelFormat, palette);
		}
		/// <summary>
		/// 複製指定點陣圖中的像素資料。
		/// </summary>
		/// <param name="bitmap">指定的點陣圖。</param>
		/// <param name="rect">要複製的矩形範圍。</param>
		/// <param name="pixelFormat">指定的像素格式。</param>
		/// <param name="palette">指定像素格式所需的調色盤。</param>
		/// <returns>表示點陣圖像素資料的位元組陣列。</returns>
		/// <exception cref="ArgumentNullException">bitmap 為 Null (Visual Basic 為 Nothing)。</exception>
		public static byte[] CopyPixelsToByteArray(this IBitmapImage bitmap, Int32Rect rect, PixelFormat pixelFormat, BitmapPalette palette)
		{
			//確認
			if (bitmap == null)
				throw new ArgumentNullException("bitmap");

			//取得複製大小
			if (rect == Int32Rect.Empty)
			{
				rect.Width = bitmap.PixelWidth;
				rect.Height = bitmap.PixelHeight;
			}

			//計算所需大小
			int stride = pixelFormat.BitsPerPixel * rect.Width / 8;
			/*
			int padding = 4 - (stride % 4);
			if (padding < 4)
				stride += padding;
			*/
			int bufferSize = (stride * rect.Height);

			//複製像素資料
			byte[] buffer = new byte[bufferSize];
			fixed (byte* bufferPtr = buffer)
			{
				bitmap.CopyPixels(rect, pixelFormat, palette, new IntPtr(bufferPtr), bufferSize, stride);
			}

			//回傳
			return buffer;
		}
		#endregion
		#region CreateSquareBitmap
		/// <summary>
		/// 使用指定的點陣圖建立矩形點陣圖。
		/// </summary>
		/// <param name="source">來源點陣圖。</param>
		/// <returns>矩形點陣圖。</returns>
		/// <exception cref="ArgumentNullException">source 為 Null (Visual Basic 為 Nothing)。</exception>
		public static IBitmapImage CreateSquareBitmap(this IBitmapImage source)
		{
			if (source == null)
				throw new ArgumentNullException("source");
			return CreateSquareBitmap(source, Math.Min(source.PixelWidth, source.PixelHeight));
		}
		/// <summary>
		/// 使用指定的點陣圖建立矩形點陣圖。
		/// </summary>
		/// <param name="source">來源點陣圖。</param>
		/// <param name="sideLength">矩形點陣圖邊長。</param>
		/// <returns>矩形點陣圖。</returns>
		/// <exception cref="ArgumentNullException">source 為 Null (Visual Basic 為 Nothing)。</exception>
		/// <exception cref="ArgumentOutOfRangeException">sideLength 不是正整數。</exception>
		public static IBitmapImage CreateSquareBitmap(this IBitmapImage source, int sideLength)
		{
			//確認參數
			if (source == null)
				throw new ArgumentNullException("source");

			//建立矩形 BitmapSource
			BitmapSource squareBitmapSource = CreateSquareBitmap(source.ToBitmapSource(), sideLength);

			//建立點陣圖
			return new BitmapImage(null, squareBitmapSource, true, source.Metadata, null);
		}
		/// <summary>
		/// 使用指定的點陣圖建立矩形點陣圖。
		/// </summary>
		/// <param name="source">來源點陣圖。</param>
		/// <returns>矩形點陣圖。</returns>
		/// <exception cref="ArgumentNullException">source 為 Null (Visual Basic 為 Nothing)。</exception>
		public static BitmapSource CreateSquareBitmap(this BitmapSource source)
		{
			if (source == null)
				throw new ArgumentNullException("source");
			return CreateSquareBitmap(source, Math.Min(source.PixelWidth, source.PixelHeight));
		}
		/// <summary>
		/// 使用指定的點陣圖建立矩形點陣圖。
		/// </summary>
		/// <param name="source">來源點陣圖。</param>
		/// <param name="sideLength">矩形點陣圖邊長。</param>
		/// <returns>矩形點陣圖。</returns>
		/// <exception cref="ArgumentNullException">source 為 Null (Visual Basic 為 Nothing)。</exception>
		/// <exception cref="ArgumentOutOfRangeException">sideLength 不是正整數。</exception>
		public static BitmapSource CreateSquareBitmap(this BitmapSource source, int sideLength)
		{
			//確認參數
			if (source == null)
				throw new ArgumentNullException("source");
			if (sideLength <= 0)
				throw new ArgumentOutOfRangeException("sideLength");

			//裁切矩形點陣圖
			BitmapSource squareBitmap;
			bool isNewBitmapCreated = false;
			if (source.PixelWidth != source.PixelHeight)
			{
				int srcSideLength = Math.Min(source.PixelWidth, source.PixelHeight);
				Int32Rect rect = new Int32Rect((source.PixelWidth - srcSideLength) / 2, (source.PixelHeight - srcSideLength) / 2, srcSideLength, srcSideLength);
				squareBitmap = new CroppedBitmap(source, rect);
				isNewBitmapCreated = true;
			}
			else
				squareBitmap = source;

			//調整大小
			if (squareBitmap.PixelWidth != sideLength)
			{
				double scale = ((double)sideLength / squareBitmap.PixelWidth);
				squareBitmap = new TransformedBitmap(source, new ScaleTransform(scale, scale));
				isNewBitmapCreated = true;
			}

			//完成
			if (isNewBitmapCreated)
				squareBitmap = CopyBitmap(squareBitmap);
			return squareBitmap;
		}
		#endregion
		#region EnsurePixelFormat
		/// <summary>
		/// 確保 BitmapSource 的像素格式符合指定格式列表中的其中一項，若不符合則轉換成預設的像素格式。
		/// </summary>
		/// <param name="bitmapSource">指定的 BitmapSource。</param>
		/// <param name="availableFormats">提供檢查使用的像素格式清單。</param>
		/// <param name="defaultFormat">預設的像素格式。</param>
		/// <param name="defaultPalette">預設像素格式所使用的調色盤。</param>
		/// <returns>已確保像素格式的 BitmapSource。</returns>
		/// <exception cref="ArgumentException">availableFormats 為空。</exception>
		/// <exception cref="ArgumentNullException">bitmapSource 或 availableFormats 為 Null (Visual Basic 為 Nothing)。</exception>
		public static BitmapSource EnsurePixelFormat(this BitmapSource bitmapSource, IList<PixelFormat> availableFormats, PixelFormat defaultFormat, BitmapPalette defaultPalette = null)
		{
			//確認參數
			if (bitmapSource == null)
				throw new ArgumentNullException("bitmapSource");
			if (availableFormats == null)
				throw new ArgumentNullException("availableFormats");
			if (availableFormats.Count == 0)
				throw new ArgumentException();

			//確認格式
			PixelFormat pixelFormat = bitmapSource.Format;
			for (int i = availableFormats.Count - 1; i >= 0; --i)
			{
				if (pixelFormat == availableFormats[i])
					return bitmapSource;
			}

			//轉成預設格式
			return new FormatConvertedBitmap(bitmapSource, defaultFormat, defaultPalette, 0.5);
		}
		#endregion
		#region EnumerateArgb
		/// <summary>
		/// 列舉指定點陣圖中每個像素的 ARGB，列舉順序由左至右，由上至下。
		/// </summary>
		/// <param name="bitmap">指定的點陣圖。</param>
		/// <param name="callback">列舉 ARGB 時所回呼的方法。</param>
		/// <returns>True 表示列舉完成，False 表示中止列舉。</returns>
		/// <exception cref="ArgumentNullException">bitmap 或 callback 為 Null (Visual Basic 為 Nothing)。</exception>
		public static unsafe bool EnumerateArgb(this IBitmapImage bitmap, EnumerateArgbCallback callback)
		{
			bool result = true;
			AccessPixelBuffer(bitmap, (IntPtr pixelBuffer, int w, int h, int stride, PixelFormat format, BitmapPalette palette, ref bool modified) =>
			{
				result = EnumerateArgb(pixelBuffer, format, palette, w, h, stride, callback);
			});
			return result;
		}
		/// <summary>
		/// 列舉指定點陣圖中每個像素的 ARGB，列舉順序由左至右，由上至下。
		/// </summary>
		/// <param name="pixelBuffer">存放點陣圖像素資料的緩衝區指標。</param>
		/// <param name="pixelFormat">點陣圖像素格式。</param>
		/// <param name="palette">點陣圖的調色盤。</param>
		/// <param name="width">點陣圖的像素寬度。</param>
		/// <param name="height">點陣圖的像素高度。</param>
		/// <param name="stride">點陣圖掃描線的寬度，或稱為步距，單位為位元組。</param>
		/// <param name="callback">列舉 ARGB 時所回呼的方法。</param>
		/// <returns>True 表示列舉完成，False 表示中止列舉。</returns>
		/// <exception cref="ArgumentException">pixelBuffer 為 IntPtr.Zero -或- pixelFormat 為不支援的格式。</exception>
		/// <exception cref="ArgumentNullException">callback 為 Null (Visual Basic 為 Nothing)。</exception>
		/// <exception cref="ArgumentOutOfRangeException">width、height 或 stride 不是正整數。</exception>
		public static unsafe bool EnumerateArgb(IntPtr pixelBuffer, PixelFormat pixelFormat, BitmapPalette palette, int width, int height, int stride, EnumerateArgbCallback callback)
		{
			//確認參數
			if (pixelBuffer == IntPtr.Zero)
				throw new ArgumentException();
			if (width <= 0 || height <= 0 || stride <= 0)
				throw new ArgumentOutOfRangeException();
			if (callback == null)
				throw new ArgumentNullException("callback");

			//列舉像素
			if (pixelFormat == PixelFormats.Bgr24)
				return EnumerateArgbFormatBgr24(pixelBuffer, palette, width, height, stride, callback);
			if (pixelFormat == PixelFormats.Bgr32)
				return EnumerateArgbFormatBgr32(pixelBuffer, palette, width, height, stride, callback);
			if (pixelFormat == PixelFormats.Bgra32)
				return EnumerateArgbFormatBgra32(pixelBuffer, palette, width, height, stride, callback);
			if (pixelFormat == PixelFormats.Rgb48)
				return EnumerateArgbFormatRgb48(pixelBuffer, palette, width, height, stride, callback);
			if (pixelFormat == PixelFormats.Rgba64)
				return EnumerateArgbFormatRgba64(pixelBuffer, palette, width, height, stride, callback);
			if (pixelFormat == PixelFormats.Rgb24)
				return EnumerateArgbFormatRgb24(pixelBuffer, palette, width, height, stride, callback);
			if (pixelFormat == PixelFormats.Bgr565)
				return EnumerateArgbFormatBgr565(pixelBuffer, palette, width, height, stride, callback);
			if (pixelFormat == PixelFormats.Indexed1)
				return EnumerateArgbFormatIndexed1(pixelBuffer, palette, width, height, stride, callback);
			if (pixelFormat == PixelFormats.Indexed2)
				return EnumerateArgbFormatIndexed2(pixelBuffer, palette, width, height, stride, callback);
			if (pixelFormat == PixelFormats.Indexed4)
				return EnumerateArgbFormatIndexed4(pixelBuffer, palette, width, height, stride, callback);
			if (pixelFormat == PixelFormats.Indexed8)
				return EnumerateArgbFormatIndexed8(pixelBuffer, palette, width, height, stride, callback);
			if (pixelFormat == PixelFormats.Gray2)
				return EnumerateArgbFormatGray2(pixelBuffer, palette, width, height, stride, callback);
			if (pixelFormat == PixelFormats.Gray4)
				return EnumerateArgbFormatGray4(pixelBuffer, palette, width, height, stride, callback);
			if (pixelFormat == PixelFormats.Gray8)
				return EnumerateArgbFormatGray8(pixelBuffer, palette, width, height, stride, callback);
			if (pixelFormat == PixelFormats.Gray16)
				return EnumerateArgbFormatGray16(pixelBuffer, palette, width, height, stride, callback);
			throw new ArgumentException();
		}
		#endregion
		#region EnumerateArgbFormatBgr24
		static bool EnumerateArgbFormatBgr24(IntPtr pixelBuffer, BitmapPalette palette, int width, int height, int stride, EnumerateArgbCallback callback)
		{
			if ((width * 3) == stride)
			{
				byte* pixelPtr = (byte*)pixelBuffer;
				for (int y = 0; y < height; ++y)
				{
					for (int x = 0; x < width; ++x, pixelPtr += 3)
					{
						if (!callback(x, y, 255, pixelPtr[2], pixelPtr[1], pixelPtr[0]))
							return false;
					}
				}
			}
			else
			{
				byte* lineBuffer = (byte*)pixelBuffer;
				for (int y = 0; y < height; ++y, lineBuffer += stride)
				{
					byte* pixelPtr = lineBuffer;
					for (int x = 0; x < width; ++x, pixelPtr += 3)
					{
						if (!callback(x, y, 255, pixelPtr[2], pixelPtr[1], pixelPtr[0]))
							return false;
					}
				}
			}
			return true;
		}
		#endregion
		#region EnumerateArgbFormatBgr32
		static bool EnumerateArgbFormatBgr32(IntPtr pixelBuffer, BitmapPalette palette, int width, int height, int stride, EnumerateArgbCallback callback)
		{
			if ((width << 2) == stride)
			{
				byte* pixelPtr = (byte*)pixelBuffer;
				for (int y = 0; y < height; ++y)
				{
					for (int x = 0; x < width; ++x, pixelPtr += 4)
					{
						if (!callback(x, y, 255, pixelPtr[2], pixelPtr[1], pixelPtr[0]))
							return false;
					}
				}
			}
			else
			{
				byte* lineBuffer = (byte*)pixelBuffer;
				for (int y = 0; y < height; ++y, lineBuffer += stride)
				{
					byte* pixelPtr = lineBuffer;
					for (int x = 0; x < width; ++x, pixelPtr += 4)
					{
						if (!callback(x, y, 255, pixelPtr[2], pixelPtr[1], pixelPtr[0]))
							return false;
					}
				}
			}
			return true;
		}
		#endregion
		#region EnumerateArgbFormatBgr565
		static bool EnumerateArgbFormatBgr565(IntPtr pixelBuffer, BitmapPalette palette, int width, int height, int stride, EnumerateArgbCallback callback)
		{
			byte* lineBuffer = (byte*)pixelBuffer;
			for (int y = 0; y < height; ++y, lineBuffer += stride)
			{
				byte* pixelPtr = lineBuffer;
				for (int x = 0; x < width; ++x, pixelPtr += 2)
				{
					int color = *(ushort*)pixelPtr;
					int r = (color >> 11);
					int g = ((color >> 5) & 0x3F);
					int b = (color & 0x1F);
					if (!callback(x, y, 255, r, g, b))
						return false;
				}
			}
			return true;
		}
		#endregion
		#region EnumerateArgbFormatBgra32
		static bool EnumerateArgbFormatBgra32(IntPtr pixelBuffer, BitmapPalette palette, int width, int height, int stride, EnumerateArgbCallback callback)
		{
			if ((width << 2) == stride)
			{
				byte* pixelPtr = (byte*)pixelBuffer;
				for (int y = 0; y < height; ++y)
				{
					for (int x = 0; x < width; ++x, pixelPtr += 4)
					{
						if (!callback(x, y, pixelPtr[3], pixelPtr[2], pixelPtr[1], pixelPtr[0]))
							return false;
					}
				}
			}
			else
			{
				byte* lineBuffer = (byte*)pixelBuffer;
				for (int y = 0; y < height; ++y, lineBuffer += stride)
				{
					byte* pixelPtr = lineBuffer;
					for (int x = 0; x < width; ++x, pixelPtr += 4)
					{
						if (!callback(x, y, pixelPtr[3], pixelPtr[2], pixelPtr[1], pixelPtr[0]))
							return false;
					}
				}
			}
			return true;
		}
		#endregion
		#region EnumerateArgbFormatGray16
		static bool EnumerateArgbFormatGray16(IntPtr pixelBuffer, BitmapPalette palette, int width, int height, int stride, EnumerateArgbCallback callback)
		{
			byte* lineBuffer = (byte*)pixelBuffer;
			for (int y = 0; y < height; ++y, lineBuffer += stride)
			{
				byte* pixelPtr = lineBuffer;
				for (int x = 0; x < width; ++x, pixelPtr += 2)
				{
					int color = *(ushort*)pixelPtr;
					if (!callback(x, y, 65536, color, color, color))
						return false;
				}
			}
			return true;
		}
		#endregion
		#region EnumerateArgbFormatGray2
		static bool EnumerateArgbFormatGray2(IntPtr pixelBuffer, BitmapPalette palette, int width, int height, int stride, EnumerateArgbCallback callback)
		{
			byte* lineBuffer = (byte*)pixelBuffer;
			for (int y = 0; y < height; ++y, lineBuffer += stride)
			{
				byte* pixelPtr = lineBuffer;
				int colorSet = 0;
				for (int x = 0; x < width; ++x)
				{
					int mod4 = (x % 4);
					if (mod4 == 0)
						colorSet = pixelPtr[0];
					else
					{
						colorSet >>= 2;
						if (mod4 == 3)
							++pixelPtr;
					}
					int color = (colorSet & 0x3);
					if (!callback(x, y, 3, color, color, color))
						return false;
				}
			}
			return true;
		}
		#endregion
		#region EnumerateArgbFormatGray4
		static bool EnumerateArgbFormatGray4(IntPtr pixelBuffer, BitmapPalette palette, int width, int height, int stride, EnumerateArgbCallback callback)
		{
			byte* lineBuffer = (byte*)pixelBuffer;
			for (int y = 0; y < height; ++y, lineBuffer += stride)
			{
				byte* pixelPtr = lineBuffer;
				int colorSet = 0;
				for (int x = 0; x < width; ++x)
				{
					if ((x % 0x1) == 0)
						colorSet = pixelPtr[0];
					else
					{
						colorSet >>= 4;
						++pixelPtr;
					}
					int color = (colorSet & 0xF);
					if (!callback(x, y, 15, color, color, color))
						return false;
				}
			}
			return true;
		}
		#endregion
		#region EnumerateArgbFormatGray8
		static bool EnumerateArgbFormatGray8(IntPtr pixelBuffer, BitmapPalette palette, int width, int height, int stride, EnumerateArgbCallback callback)
		{
			byte* lineBuffer = (byte*)pixelBuffer;
			for (int y = 0; y < height; ++y, lineBuffer += stride)
			{
				byte* pixelPtr = lineBuffer;
				for (int x = 0; x < width; ++x, ++pixelPtr)
				{
					int color = pixelPtr[0];
					if (!callback(x, y, 255, color, color, color))
						return false;
				}
			}
			return true;
		}
		#endregion
		#region EnumerateArgbFormatIndexed1
		static bool EnumerateArgbFormatIndexed1(IntPtr pixelBuffer, BitmapPalette palette, int width, int height, int stride, EnumerateArgbCallback callback)
		{
			if (palette == null)
				throw new ArgumentNullException("palette");
			Color[] colors = palette.Colors.ToArray();
			if (colors.Length < 2)
				throw new ArgumentException();
			byte* lineBuffer = (byte*)pixelBuffer;
			for (int y = 0; y < height; ++y, lineBuffer += stride)
			{
				byte* pixelPtr = lineBuffer;
				int colorIndexSet = 0;
				for (int x = 0; x < width; ++x)
				{
					int mod8 = (x % 8);
					if (mod8 == 0)
						colorIndexSet = pixelPtr[0];
					else
					{
						colorIndexSet >>= 1;
						if (mod8 == 7)
							++pixelPtr;
					}
					Color color = colors[colorIndexSet & 0x1];
					if (!callback(x, y, color.A, color.R, color.G, color.B))
						return false;
				}
			}
			return true;
		}
		#endregion
		#region EnumerateArgbFormatIndexed2
		static bool EnumerateArgbFormatIndexed2(IntPtr pixelBuffer, BitmapPalette palette, int width, int height, int stride, EnumerateArgbCallback callback)
		{
			if (palette == null)
				throw new ArgumentNullException("palette");
			Color[] colors = palette.Colors.ToArray();
			if (colors.Length < 4)
				throw new ArgumentException();
			byte* lineBuffer = (byte*)pixelBuffer;
			for (int y = 0; y < height; ++y, lineBuffer += stride)
			{
				byte* pixelPtr = lineBuffer;
				int colorIndexSet = 0;
				for (int x = 0; x < width; ++x)
				{
					int mod4 = (x % 4);
					if (mod4 == 0)
						colorIndexSet = pixelPtr[0];
					else
					{
						colorIndexSet >>= 2;
						if (mod4 == 3)
							++pixelPtr;
					}
					Color color = colors[colorIndexSet & 0x3];
					if (!callback(x, y, color.A, color.R, color.G, color.B))
						return false;
				}
			}
			return true;
		}
		#endregion
		#region EnumerateArgbFormatIndexed4
		static bool EnumerateArgbFormatIndexed4(IntPtr pixelBuffer, BitmapPalette palette, int width, int height, int stride, EnumerateArgbCallback callback)
		{
			if (palette == null)
				throw new ArgumentNullException("palette");
			Color[] colors = palette.Colors.ToArray();
			if (colors.Length < 16)
				throw new ArgumentException();
			byte* lineBuffer = (byte*)pixelBuffer;
			for (int y = 0; y < height; ++y, lineBuffer += stride)
			{
				byte* pixelPtr = lineBuffer;
				int colorIndexSet = 0;
				for (int x = 0; x < width; ++x)
				{
					if ((x & 0x1) == 0)
						colorIndexSet = pixelPtr[0];
					else
					{
						colorIndexSet >>= 4;
						++pixelPtr;
					}
					Color color = colors[colorIndexSet & 0xF];
					if (!callback(x, y, color.A, color.R, color.G, color.B))
						return false;
				}
			}
			return true;
		}
		#endregion
		#region EnumerateArgbFormatIndexed8
		static bool EnumerateArgbFormatIndexed8(IntPtr pixelBuffer, BitmapPalette palette, int width, int height, int stride, EnumerateArgbCallback callback)
		{
			if (palette == null)
				throw new ArgumentNullException("palette");
			Color[] colors = palette.Colors.ToArray();
			if (colors.Length < 256)
				throw new ArgumentException();
			byte* lineBuffer = (byte*)pixelBuffer;
			for (int y = 0; y < height; ++y, lineBuffer += stride)
			{
				byte* pixelPtr = lineBuffer;
				for (int x = 0; x < width; ++x, ++pixelPtr)
				{
					Color color = colors[pixelPtr[0]];
					if (!callback(x, y, color.A, color.R, color.G, color.B))
						return false;
				}
			}
			return true;
		}
		#endregion
		#region EnumerateArgbFormatRgb24
		static bool EnumerateArgbFormatRgb24(IntPtr pixelBuffer, BitmapPalette palette, int width, int height, int stride, EnumerateArgbCallback callback)
		{
			byte* lineBuffer = (byte*)pixelBuffer;
			for (int y = 0; y < height; ++y, lineBuffer += stride)
			{
				byte* pixelPtr = lineBuffer;
				for (int x = 0; x < width; ++x, pixelPtr += 3)
				{
					if (!callback(x, y, 255, pixelPtr[0], pixelPtr[1], pixelPtr[2]))
						return false;
				}
			}
			return true;
		}
		#endregion
		#region EnumerateArgbFormatRgb48
		static bool EnumerateArgbFormatRgb48(IntPtr pixelBuffer, BitmapPalette palette, int width, int height, int stride, EnumerateArgbCallback callback)
		{
			if ((width * 6) == stride)
			{
				ushort* pixelPtr = (ushort*)pixelBuffer;
				for (int y = 0; y < height; ++y)
				{
					for (int x = 0; x < width; ++x, pixelPtr += 3)
					{
						if (!callback(x, y, 65535, pixelPtr[0], pixelPtr[1], pixelPtr[2]))
							return false;
					}
				}
			}
			else
			{
				byte* lineBuffer = (byte*)pixelBuffer;
				for (int y = 0; y < height; ++y, lineBuffer += stride)
				{
					ushort* pixelPtr = (ushort*)lineBuffer;
					for (int x = 0; x < width; ++x, pixelPtr += 3)
					{
						if (!callback(x, y, 65535, pixelPtr[0], pixelPtr[1], pixelPtr[2]))
							return false;
					}
				}
			}
			return true;
		}
		#endregion
		#region EnumerateArgbFormatRgba64
		static bool EnumerateArgbFormatRgba64(IntPtr pixelBuffer, BitmapPalette palette, int width, int height, int stride, EnumerateArgbCallback callback)
		{
			byte* lineBuffer = (byte*)pixelBuffer;
			for (int y = 0; y < height; ++y, lineBuffer += stride)
			{
				byte* pixelPtr = lineBuffer;
				for (int x = 0; x < width; ++x, pixelPtr += 8)
				{
					if (!callback(x, y, *(ushort*)(pixelPtr + 6), *(ushort*)(pixelPtr), *(ushort*)(pixelPtr + 2), *(ushort*)(pixelPtr + 4)))
						return false;
				}
			}
			return true;
		}
		#endregion
		#region EstimatePixelBufferSize
		/// <summary>
		/// 估計點陣圖像素緩衝區所需佔用的位元組大小。
		/// </summary>
		/// <param name="bitmap">指定的點陣圖。</param>
		/// <returns>估計需佔用的位元組大小。</returns>
		/// <exception cref="ArgumentNullException">bitmap 為 Null (Visual Basic 為 Nothing)。</exception>
		public static long EstimatePixelBufferSize(IBitmapImage bitmap)
		{
			//確認參數
			if (bitmap == null)
				throw new ArgumentNullException("bitmap");

			//計算步距
			int stride = 0;
			if (bitmap.HasDirectPixelBuffer)
				stride = bitmap.PixelBufferStride;
			if (stride <= 0)
			{
				stride = (int)Math.Ceiling(bitmap.PixelWidth * bitmap.PixelFormat.BitsPerPixel / 8.0 + 0.001);
				int extraBytes = (stride % 4);
				if (extraBytes > 0)
					stride += 4;
			}

			//計算大小
			return (stride * bitmap.PixelHeight);
		}
		#endregion
		#region GetAsBitmapSource
		/// <summary>
		/// 將指定的 ImageSource 物件轉成 BitmapSource 物件，若原本的 ImageSource 物件已是 BitmapSource 則直接傳回該物件。
		/// </summary>
		/// <param name="imageSource">指定的 ImageSource。</param>
		/// <returns>BitmapSource 物件。</returns>
		/// <exception cref="ArgumentNullException">imageSource 為 Null (Visual Basic 為 Nothing)。</exception>
		public static BitmapSource GetAsBitmapSource(this ImageSource imageSource)
		{
			//確認
			if (imageSource == null)
				throw new ArgumentNullException("imageSource");
			if (imageSource is BitmapSource)
				return imageSource as BitmapSource;

			//轉成 BitmapSource
			RenderTargetBitmap bmpSource = new RenderTargetBitmap((int)Math.Ceiling(imageSource.Width), (int)Math.Ceiling(imageSource.Height), 96, 96, PixelFormats.Bgra32);
			System.Windows.Controls.Image image = new System.Windows.Controls.Image();
			image.Source = imageSource;
			bmpSource.Render(image);

			//回傳
			return bmpSource;
		}
		#endregion
		#region GetAsIBitmapImage
		/// <summary>
		/// 將指定的 ImageSource 物件轉成 IBitmapImage 介面。
		/// </summary>
		/// <param name="imageSource">指定的 ImageSource。</param>
		/// <returns>IBitmapImage 介面。</returns>
		/// <exception cref="ArgumentNullException">imageSource 為 Null (Visual Basic 為 Nothing)。</exception>
		public static IBitmapImage GetAsIBitmapImage(this ImageSource imageSource)
		{
			if (imageSource == null)
				throw new ArgumentNullException("imageSource");
			return new BitmapImage(imageSource.GetAsBitmapSource());
		}
		#endregion
		#region GetAsIImage
		/// <summary>
		/// 將指定的 ImageSource 物件轉成 IImage 介面。
		/// </summary>
		/// <param name="imageSource">指定的 ImageSource。</param>
		/// <returns>IImage 介面。</returns>
		/// <exception cref="ArgumentNullException">imageSource 為 Null (Visual Basic 為 Nothing)。</exception>
		public static IImage GetAsIImage(ImageSource imageSource)
		{
			return GetAsIBitmapImage(imageSource);
		}
		#endregion
		#region GetImageFileCount
		/// <summary>
		/// 取得指定目錄中所有支援的影像數量。
		/// </summary>
		/// <param name="directory">指定的目錄。</param>
		/// <returns>目錄中的影像數量。</returns>
		/// <exception cref="ArgumentException">無效的目錄路徑。</exception>
		/// <exception cref="ArgumentNullException">directory 為 Null (Visual Basic 為 Nothing)。</exception>
		public static int GetImageFileCount(string directory)
		{
			return GetImageFileCount(directory, null);
		}
		/// <summary>
		/// 取得指定目錄中的影像數量。
		/// </summary>
		/// <param name="directory">指定的目錄。</param>
		/// <param name="format">指定的影像格式，Null (Visual Basic 為 Nothing) 表示所有解碼器支援的格式。</param>
		/// <returns>目錄中的影像數量。</returns>
		/// <exception cref="ArgumentException">無效的目錄路徑。</exception>
		/// <exception cref="ArgumentNullException">directory 為 Null (Visual Basic 為 Nothing)。</exception>
		public static int GetImageFileCount(string directory, IMediaFormat format)
		{
			return GetImageFileNames(directory, format).Length;
		}
		#endregion
		#region GetImageFileNames
		/// <summary>
		/// 取得指定目錄中的所有支援的影像檔案路徑。
		/// </summary>
		/// <param name="directory">指定的目錄。</param>
		/// <returns>表示影像檔案路徑的字串陣列。</returns>
		/// <exception cref="ArgumentException">無效的目錄路徑。</exception>
		/// <exception cref="ArgumentNullException">directory 為 Null (Visual Basic 為 Nothing)。</exception>
		public static string[] GetImageFileNames(string directory)
		{
			return GetImageFileNames(directory, null);
		}
		/// <summary>
		/// 取得指定目錄中的影像檔案路徑。
		/// </summary>
		/// <param name="directory">指定的目錄。</param>
		/// <param name="format">指定的影像格式，Null (Visual Basic 為 Nothing) 表示所有解碼器支援的格式。</param>
		/// <returns>表示影像檔案路徑的字串陣列。</returns>
		/// <exception cref="ArgumentException">無效的目錄路徑。</exception>
		/// <exception cref="ArgumentNullException">directory 為 Null (Visual Basic 為 Nothing)。</exception>
		public static string[] GetImageFileNames(string directory, IMediaFormat format)
		{
			//確認
			if (directory == null)
				throw new ArgumentNullException("directory");
			if (!FileUtility.IsValidPath(directory))
				throw new ArgumentException();

			//取得檔案路徑
			HashSet<string> fileNames = new HashSet<string>(PathComparer.Default);
			if (format == null)		//=====取得所有支援的格式=====
			{
				foreach (string extension in ImageCodecs.GetDecodingFormatFileNameExtensions())
				{
					try
					{
						string[] fileNameArray = Directory.GetFiles(directory, "*" + extension);
						for (int i = 0, count = fileNameArray.Length; i < count; i++)
							fileNames.Add(fileNameArray[i]);
					}
					catch (DirectoryNotFoundException ex)
					{
						break;
					}
					catch (UnauthorizedAccessException ex)
					{
						break;
					}
					catch
					{ }
				}
			}
			else					//=====取得指定的格式=====
			{
				//取得支援的副檔名
				string[] extensions;
				try
				{
					extensions = format.FileNameExtensions;
				}
				catch
				{
					return new string[0];
				}

				//取得影像檔案
				for (int i = 0, count = extensions.Length; i < count; i++)
				{
					try
					{
						string[] fileNameArray = Directory.GetFiles(directory, "*" + extensions[i]);
						for (int j = 0, length = fileNameArray.Length; j < length; j++)
							fileNames.Add(fileNameArray[j]);
					}
					catch (DirectoryNotFoundException ex)
					{
						break;
					}
					catch (UnauthorizedAccessException ex)
					{
						break;
					}
					catch
					{ }
				}
			}

			//回傳
			string[] array = new string[fileNames.Count];
			fileNames.CopyTo(array, 0);
			return array;
		}
		#endregion
		#region GetImageFiles
		/// <summary>
		/// 取得指定目錄中的影像檔案資訊。
		/// </summary>
		/// <param name="directory">指定的目錄。</param>
		/// <returns>包含影像檔案資訊的 System.IO.FileInfo 陣列。</returns>
		/// <exception cref="ArgumentNullException">directory 參數值為 Null (Visual Basic 為 Nothing)。</exception>
		/// <exception cref="ArgumentException">無效的目錄路徑。</exception>
		public static FileInfo[] GetImageFiles(string directory)
		{
			return GetImageFiles(directory, null);
		}
		/// <summary>
		/// 取得指定目錄中指定格式的影像檔案資訊。
		/// </summary>
		/// <param name="directory">指定的目錄。</param>
		/// <param name="format">指定的影像格式，Null (Visual Basic 為 Nothing) 表示所有解碼器支援的格式。。</param>
		/// <returns>包含影像檔案資訊的 System.IO.FileInfo 陣列。</returns>
		/// <exception cref="ArgumentNullException">directory 參數值為 Null (Visual Basic 為 Nothing)。</exception>
		/// <exception cref="ArgumentException">無效的目錄路徑。</exception>
		public static FileInfo[] GetImageFiles(string directory, IMediaFormat format)
		{
			//取得檔案名稱
			string[] fileNames = GetImageFileNames(directory, format);

			//建立物件
			int count = fileNames.Length;
			FileInfo[] fileInfos = new FileInfo[count];
			for (int i = count - 1; i >= 0; i--)
				fileInfos[i] = new FileInfo(fileNames[i]);

			//回傳
			return fileInfos;
		}
		#endregion	
		#region GetMaximumBitmap
		/// <summary>
		/// 在指定的多重影像中搜尋最大的點陣圖。
		/// </summary>
		/// <param name="multiImage">指定的多重影像。</param>
		/// <returns>最大點陣圖，Null (Visual Basic 為 Nothing) 表示無法搜尋到點陣圖。</returns>
		/// <exception cref="ArgumentNullException">multiImage 為 Null (Visual Basic 為 Nothing)。</exception>
		public static IBitmapImage GetMaximumBitmap(this IMultiImage multiImage)
		{
			return GetMaximumBitmap(multiImage, null, null);
		}
		/// <summary>
		/// 在指定的多重影像中搜尋最大的點陣圖。
		/// </summary>
		/// <param name="multiImage">指定的多重影像。</param>
		/// <param name="maxPixelWidth">像素寬度上限，Null (Visual Basic 為 Nothing) 表示無上限。</param>
		/// <param name="maxPixelHeight">像素高度上限，Null (Visual Basic 為 Nothing) 表示無上限。</param>
		/// <returns>符合指定像素大小的最大點陣圖，Null (Visual Basic 為 Nothing) 表示無法搜尋到符合條件的點陣圖。</returns>
		/// <exception cref="ArgumentNullException">multiImage 為 Null (Visual Basic 為 Nothing)。</exception>
		public static IBitmapImage GetMaximumBitmap(this IMultiImage multiImage, int? maxPixelWidth, int? maxPixelHeight)
		{
			if (multiImage == null)
				throw new ArgumentNullException("multiImage");
			return GetNearstImage(new HashSet<IImage>(), multiImage, maxPixelWidth, maxPixelHeight, true);
		}
		#endregion
		#region GetMaximumPixelSize
		/// <summary>
		/// 在指定的多重影像中搜尋最大的點陣圖像素大小。
		/// </summary>
		/// <param name="multiImage">指定的多重影像。</param>
		/// <returns>最大點陣圖像素大小，Null (Visual Basic 為 Nothing) 表示無法搜尋到點陣圖。</returns>
		/// <exception cref="ArgumentNullException">multiImage 為 Null (Visual Basic 為 Nothing)。</exception>
		public static Size? GetMaximumPixelSize(this IMultiImage multiImage)
		{
			return GetMaximumPixelSize(multiImage, null, null);
		}
		/// <summary>
		/// 在指定的多重影像中搜尋最大的點陣圖像素大小。
		/// </summary>
		/// <param name="multiImage">指定的多重影像。</param>
		/// <param name="maxPixelWidth">像素寬度上限，Null (Visual Basic 為 Nothing) 表示無上限。</param>
		/// <param name="maxPixelHeight">像素高度上限，Null (Visual Basic 為 Nothing) 表示無上限。</param>
		/// <returns>符合指定像素大小的最大點陣圖像素大小，Null (Visual Basic 為 Nothing) 表示無法搜尋到符合條件的點陣圖。</returns>
		/// <exception cref="ArgumentNullException">multiImage 為 Null (Visual Basic 為 Nothing)。</exception>
		public static Size? GetMaximumPixelSize(this IMultiImage multiImage, int? maxPixelWidth, int? maxPixelHeight)
		{
			IBitmapImage bitmap = GetMaximumBitmap(multiImage, maxPixelWidth, maxPixelHeight);
			if (bitmap != null)
				return new Size(bitmap.PixelWidth, bitmap.PixelHeight);
			return null;
		}
		#endregion
		#region GetMinimumBitmap
		/// <summary>
		/// 在指定的多重影像中搜尋最小的點陣圖。
		/// </summary>
		/// <param name="multiImage">指定的多重影像。</param>
		/// <returns>最小點陣圖，Null (Visual Basic 為 Nothing) 表示無法搜尋到點陣圖。</returns>
		/// <exception cref="ArgumentNullException">multiImage 為 Null (Visual Basic 為 Nothing)。</exception>
		public static IBitmapImage GetMinimumBitmap(this IMultiImage multiImage)
		{
			return GetMinimumBitmap(multiImage, null, null);
		}
		/// <summary>
		/// 在指定的多重影像中搜尋最小的點陣圖。
		/// </summary>
		/// <param name="multiImage">指定的多重影像。</param>
		/// <param name="minPixelWidth">像素寬度下限，Null (Visual Basic 為 Nothing) 表示無下限。</param>
		/// <param name="minPixelHeight">像素高度下限，Null (Visual Basic 為 Nothing) 表示無下限。</param>
		/// <returns>符合指定像素大小的最小點陣圖，Null (Visual Basic 為 Nothing) 表示無法搜尋到符合條件的點陣圖。</returns>
		/// <exception cref="ArgumentNullException">multiImage 為 Null (Visual Basic 為 Nothing)。</exception>
		public static IBitmapImage GetMinimumBitmap(this IMultiImage multiImage, int? minPixelWidth, int? minPixelHeight)
		{
			if (multiImage == null)
				throw new ArgumentNullException("multiImage");
			return GetNearstImage(new HashSet<IImage>(), multiImage, minPixelWidth, minPixelHeight, false);
		}
		#endregion
		#region GetMinimumPixelSize
		/// <summary>
		/// 在指定的多重影像中搜尋最小的點陣圖像素大小。
		/// </summary>
		/// <param name="multiImage">指定的多重影像。</param>
		/// <returns>最小點陣圖像素大小，Null (Visual Basic 為 Nothing) 表示無法搜尋到點陣圖。</returns>
		/// <exception cref="ArgumentNullException">multiImage 為 Null (Visual Basic 為 Nothing)。</exception>
		public static Size? GetMinimumPixelSize(this IMultiImage multiImage)
		{
			return GetMinimumPixelSize(multiImage, null, null);
		}
		/// <summary>
		/// 在指定的多重影像中搜尋最小的點陣圖像素大小。
		/// </summary>
		/// <param name="multiImage">指定的多重影像。</param>
		/// <param name="minPixelWidth">像素寬度下限，Null (Visual Basic 為 Nothing) 表示無下限。</param>
		/// <param name="minPixelHeight">像素高度下限，Null (Visual Basic 為 Nothing) 表示無下限。</param>
		/// <returns>符合指定像素大小的最小點陣圖像素大小，Null (Visual Basic 為 Nothing) 表示無法搜尋到符合條件的點陣圖。</returns>
		/// <exception cref="ArgumentNullException">multiImage 為 Null (Visual Basic 為 Nothing)。</exception>
		public static Size? GetMinimumPixelSize(this IMultiImage multiImage, int? minPixelWidth, int? minPixelHeight)
		{
			IBitmapImage bitmap = GetMinimumBitmap(multiImage, minPixelWidth, minPixelHeight);
			if (bitmap != null)
				return new Size(bitmap.PixelWidth, bitmap.PixelHeight);
			return null;
		}
		#endregion
		#region GetNearstImage
		private static IBitmapImage GetNearstImage(HashSet<IImage> checkedImages, IMultiImage multiImage, int? boundPixelWidth, int? boundPixelHeight, bool findMaxImage)
		{
			if (!checkedImages.Add(multiImage))
				return null;
			IBitmapImage candImage = null;
			IList<IImage> imageList = multiImage.Images;
			if (imageList != null)
			{
				for (int i = imageList.Count - 1; i >= 0; --i)
				{
					//取得點陣圖
					IBitmapImage bitmap = (imageList[i] as IBitmapImage);
					if (bitmap == null)
					{
						IMultiImage subMultiImage = (imageList[i] as IMultiImage);
						if (subMultiImage != null)
							bitmap = GetNearstImage(checkedImages, subMultiImage, boundPixelWidth, boundPixelHeight, findMaxImage);
					}

					//確認是否為最接近影像
					if (bitmap != null)
					{
						//確認是否符合大小條件
						if (findMaxImage)
						{
							if (boundPixelWidth != null && boundPixelWidth < bitmap.PixelWidth)
								continue;
							if (boundPixelHeight != null && boundPixelHeight < bitmap.PixelHeight)
								continue;
						}
						else
						{
							if (boundPixelWidth != null && boundPixelWidth > bitmap.PixelWidth)
								continue;
							if (boundPixelHeight != null && boundPixelHeight > bitmap.PixelHeight)
								continue;
						}

						//確認是否為最接近影像
						if (candImage == null)
							candImage = bitmap;
						else if (findMaxImage)
						{
							if (candImage.PixelWidth > bitmap.PixelWidth || candImage.PixelHeight > bitmap.PixelHeight)
								continue;
							if (candImage.PixelWidth == bitmap.PixelWidth && candImage.PixelHeight == bitmap.PixelHeight && candImage.PixelFormat.BitsPerPixel >= bitmap.PixelFormat.BitsPerPixel)
								continue;
							candImage = bitmap;
						}
						else
						{
							if (candImage.PixelWidth < bitmap.PixelWidth || candImage.PixelHeight < bitmap.PixelHeight)
								continue;
							if (candImage.PixelWidth == bitmap.PixelWidth && candImage.PixelHeight == bitmap.PixelHeight && candImage.PixelFormat.BitsPerPixel >= bitmap.PixelFormat.BitsPerPixel)
								continue;
							candImage = bitmap;
						}
					}
				}
			}
			return candImage;
		}
		#endregion
		#region GetThumbnailImage
		/// <summary>
		/// 取得指定影像的縮圖，解析度為 96 DPI。
		/// </summary>
		/// <param name="image">指定的影像。</param>
		/// <param name="bounds">縮圖的邊界大小。</param>
		/// <returns>縮圖影像。</returns>
		/// <exception cref="ArgumentNullException">image 為 Null (Visual Basic 為 Nothing)。</exception>
		public static ImageSource GetThumbnailImage(this IImage image, Size<double> bounds)
		{
			return GetThumbnailImage(image, bounds, 96, 96);
		}
		/// <summary>
		/// 取得指定影像的縮圖。
		/// </summary>
		/// <param name="image">指定的影像。</param>
		/// <param name="bounds">縮圖的邊界大小。</param>
		/// <param name="dpiX">縮圖的水平解析度 (DPI)。</param>
		/// <param name="dpiY">縮圖的垂直解析度 (DPI)。</param>
		/// <returns>縮圖影像。</returns>
		/// <exception cref="ArgumentNullException">image 為 Null (Visual Basic 為 Nothing)。</exception>
		/// <exception cref="ArgumentOutOfRangeException">dpiX 或 dpiY 小於或等於零。</exception>
		public static ImageSource GetThumbnailImage(this IImage image, Size<double> bounds, double dpiX, double dpiY)
		{
			//確認
			if (image == null)
				throw new ArgumentNullException("image");
			if (dpiX <= 0 || dpiY <= 0)
				throw new ArgumentOutOfRangeException();

			//取得點陣圖
			BitmapSource bmpSource = image.ToImageSource().GetAsBitmapSource();
			Size<double> thumbSize = LayoutUtility.GetRatioStretchSize(bounds, new Size<double>(bmpSource.Width, bmpSource.Height), StretchDirection.DownOnly);

			//建立縮圖
			double ratio = (thumbSize.Width / bmpSource.PixelWidth);
			double ratioX = ratio * (bmpSource.DpiX / dpiX);
			double ratioY = ratio * (bmpSource.DpiY / dpiY);
			return new TransformedBitmap(bmpSource, new ScaleTransform(ratioX, ratioY)).GetAsFrozen() as ImageSource;
		}
		#endregion
		#region Is16BitsColor
		/// <summary>
		/// 確認指定的像素格式是否使用 16 位元表示單一色彩。
		/// </summary>
		/// <param name="pixelFormat">指定的像素格式。</param>
		/// <returns>True 表示使用 16 位元表示單一色彩，False 則不是。</returns>
		public static bool Is16BitsColor(this PixelFormat pixelFormat)
		{
			return (pixelFormat == PixelFormats.Rgb48
				|| pixelFormat == PixelFormats.Rgba64
				|| pixelFormat == PixelFormats.Gray16
			);
		}
		#endregion
		#region Is8BitsColor
		/// <summary>
		/// 確認指定的像素格式是否使用 8 位元表示單一色彩。
		/// </summary>
		/// <param name="pixelFormat">指定的像素格式。</param>
		/// <returns>True 表示使用 8 位元表示單一色彩，False 則不是。</returns>
		public static bool Is8BitsColor(this PixelFormat pixelFormat)
		{
			return (pixelFormat == PixelFormats.Bgr24
				|| pixelFormat == PixelFormats.Bgr32
				|| pixelFormat == PixelFormats.Bgra32
				|| pixelFormat == PixelFormats.Rgb24
				|| pixelFormat == PixelFormats.Indexed1
				|| pixelFormat == PixelFormats.Indexed2
				|| pixelFormat == PixelFormats.Indexed4
				|| pixelFormat == PixelFormats.Indexed8
				|| pixelFormat == PixelFormats.Gray8
			);
		}
		#endregion
		#region Is96Dpi
		/// <summary>
		/// 確認指定的點陣圖解析度是否為 96 DPI。
		/// </summary>
		/// <param name="bitmap">指定的點陣圖。</param>
		/// <returns>點陣圖解析度是否為 96 DPI。</returns>
		/// <exception cref="ArgumentNullException">bitmap 為 Null (Visual Basic 為 Nothing)。</exception>
		public static bool Is96Dpi(this IBitmapImage bitmap)
		{
			if (bitmap == null)
				throw new ArgumentNullException("bitmap");
			return (Math.Abs(bitmap.DpiX - 96) <= 0.01 && Math.Abs(bitmap.DpiY - 96) <= 0.01);
		}
		/// <summary>
		/// 確認指定的點陣圖解析度是否為 96 DPI。
		/// </summary>
		/// <param name="bitmap">指定的點陣圖。</param>
		/// <returns>點陣圖解析度是否為 96 DPI。</returns>
		/// <exception cref="ArgumentNullException">bitmap 為 Null (Visual Basic 為 Nothing)。</exception>
		public static bool Is96Dpi(this BitmapSource bitmap)
		{
			if (bitmap == null)
				throw new ArgumentNullException("bitmap");
			return (Math.Abs(bitmap.DpiX - 96) <= 0.01 && Math.Abs(bitmap.DpiY - 96) <= 0.01);
		}
		#endregion
		#region ToBitmapSource
		/// <summary>
		/// 將指定的 System.Drawing.Bitmap 轉換成對應的 System.Windows.Media.Imaging.BitmapSource。
		/// </summary>
		/// <param name="bitmap">指定的 System.Drawing.Bitmap。</param>
		/// <returns>對應的 System.Windows.Media.Imaging.BitmapSource。</returns>
		/// <exception cref="ArgumentNullException">bitmapSource 為 Null (Visual Basic 為 Nothing)。</exception>
		/// <exception cref="NotSupportedException">轉換失敗。</exception>
		public static BitmapSource ToBitmapSource(this Gdi.Bitmap bitmap)
		{
			BitmapSource bitmapSource;
			if (bitmap.TryConvertToBitmapSource(out bitmapSource))
				return bitmapSource;
			throw new NotSupportedException();
		}
		/// <summary>
		/// 將指定的影像轉換成對應的 System.Windows.Media.Imaging.BitmapSource。
		/// </summary>
		/// <param name="image">指定的影像。</param>
		/// <returns>對應的 System.Windows.Media.Imaging.BitmapSource。</returns>
		/// <exception cref="ArgumentNullException">image 為 Null (Visual Basic 為 Nothing)。</exception>
		public static BitmapSource ToBitmapSource(this IImage image)
		{
			if (image == null)
				throw new ArgumentNullException("image");
			return image.ToImageSource().GetAsBitmapSource();
		}
        #endregion
		#region ToGdiBitmap
		/// <summary>
		/// 將指定的 System.Windows.Media.Imaging.BitmapSource 轉換成對應的 System.Drawing.Bitmap。
		/// </summary>
		/// <param name="bitmapSource">指定的 System.Windows.Media.Imaging.BitmapSource。</param>
		/// <returns>對應的 System.Drawing.Bitmap。</returns>
		/// <exception cref="ArgumentNullException">bitmapSource 為 Null (Visual Basic 為 Nothing)。</exception>
		/// <exception cref="NotSupportedException">轉換失敗。</exception>
		public static Gdi.Bitmap ToGdiBitmap(this BitmapSource bitmapSource)
		{
			Gdi.Bitmap bitmap;
			if (bitmapSource.TryConvertToGdiBitmap(out bitmap))
				return bitmap;
			throw new NotSupportedException();
		}
		/// <summary>
		/// 將指定的影像轉換成對應的 System.Drawing.Bitmap。
		/// </summary>
		/// <param name="image">指定的影像。</param>
		/// <returns>對應的 System.Drawing.Bitmap。</returns>
		/// <exception cref="ArgumentNullException">image 為 Null (Visual Basic 為 Nothing)。</exception>
		/// <exception cref="NotSupportedException">轉換失敗。</exception>
		public static Gdi.Bitmap ToGdiBitmap(this IImage image)
		{
			return image.ToBitmapSource().ToGdiBitmap();
		}
        #endregion
		#region TryConvertToBitmapSource
		/// <summary>
		/// 嘗試將指定的 System.Drawing.Bitmap 轉換成對應的 System.Windows.Media.Imaging.BitmapSource。
		/// </summary>
		/// <param name="bitmap">指定的 System.Drawing.Bitmap。</param>
		/// <param name="bitmapSource">對應的 System.Windows.Media.Imaging.BitmapSource。</param>
		/// <returns>True 表示轉換成功，False 表示失敗。</returns>
		/// <exception cref="ArgumentNullException">bitmapSource 為 Null (Visual Basic 為 Nothing)。</exception>
		public static bool TryConvertToBitmapSource(this Gdi.Bitmap bitmap, out BitmapSource bitmapSource)
		{
			//初始化參數
			bitmapSource = null;

			//確認參數
			if (bitmap == null)
				throw new ArgumentNullException("bitmap");

			//取得對應的像素格式
			bool isPaletteNeeded = (bitmap.Palette != null && bitmap.Palette.Entries.Length > 0);
			PixelFormat pixelFormat;
			GdiImaging.PixelFormat gdiPixelFormat = bitmap.PixelFormat;
			if (!gdiPixelFormat.TryConvertToPixelFormat(out pixelFormat))
			{
				gdiPixelFormat = GdiImaging.PixelFormat.Format32bppArgb;
				pixelFormat = PixelFormats.Bgra32;
				isPaletteNeeded = false;
			}

			//轉成 BitmapSource
			GdiImaging.BitmapData bitmapData = bitmap.LockBits(new Gdi.Rectangle(0, 0, bitmap.Width, bitmap.Height), GdiImaging.ImageLockMode.ReadOnly, gdiPixelFormat);
			try
			{
				//複製調色盤
				BitmapPalette palette;
				if (isPaletteNeeded)
				{
					GdiImaging.ColorPalette gdiPalette = bitmap.Palette;
					Color[] colors = new Color[gdiPalette.Entries.Length];
					for (int i = colors.Length - 1; i >= 0; --i)
					{
						Gdi.Color color = gdiPalette.Entries[i];
						colors[i] = Color.FromArgb(color.A, color.R, color.G, color.B);
					}
					palette = new BitmapPalette(colors);
				}
				else
					palette = null;

				//複製像素資料
				byte[] pixels = new byte[bitmapData.Stride * bitmapData.Height];
				Marshal.Copy(bitmapData.Scan0, pixels, 0, pixels.Length);
				bitmapSource = BitmapSource.Create(bitmapData.Width, bitmapData.Height, bitmap.HorizontalResolution, bitmap.VerticalResolution, pixelFormat, palette, pixels, bitmapData.Stride);
			}
			finally
			{
				bitmap.UnlockBits(bitmapData);
			}

			//完成
			return true;
		}
        #endregion
		#region TryConvertToGdiBitmap
		/// <summary>
		/// 嘗試將指定的 System.Windows.Media.Imaging.BitmapSource 轉換成對應的 System.Drawing.Bitmap。
		/// </summary>
		/// <param name="bitmapSource">指定的 System.Windows.Media.Imaging.BitmapSource。</param>
		/// <param name="bitmap">對應的 System.Drawing.Bitmap。</param>
		/// <returns>True 表示轉換成功，False 表示失敗。</returns>
		/// <exception cref="ArgumentNullException">bitmapSource 為 Null (Visual Basic 為 Nothing)。</exception>
		public static bool TryConvertToGdiBitmap(this BitmapSource bitmapSource, out Gdi.Bitmap bitmap)
		{
			//初始化參數
			bitmap = null;

			//確認參數
			if (bitmapSource == null)
				throw new ArgumentNullException("bitmapSource");

			//取得像素格式
			bool isPaletteNeeded = (bitmapSource.Palette != null && bitmapSource.Palette.Colors.Count > 0);
			PixelFormat pixelFormat = bitmapSource.Format;
			GdiImaging.PixelFormat gdiPixelFormat;
			if (!bitmapSource.Format.TryConvertToGdiPixelFormat(out gdiPixelFormat))
			{
				pixelFormat = PixelFormats.Bgra32;
				gdiPixelFormat = GdiImaging.PixelFormat.Format32bppArgb;
				isPaletteNeeded = false;
			}

			//複製點陣圖
			try
			{
				//建立 GDI 點陣圖
				bitmap = new Gdi.Bitmap(bitmapSource.PixelWidth, bitmapSource.PixelHeight, gdiPixelFormat);

				//複製像素資料
				GdiImaging.BitmapData bitmapData = bitmap.LockBits(new Gdi.Rectangle(0, 0, bitmap.Width, bitmap.Height), GdiImaging.ImageLockMode.WriteOnly, gdiPixelFormat);
				try
				{
					byte[] pixels = new byte[bitmapData.Stride * bitmapData.Height];
					bitmapSource.CopyPixels(pixels, bitmapData.Stride, 0);
					Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length);
				}
				finally
				{
					bitmap.UnlockBits(bitmapData);
				}

				//複製調色盤
				if (isPaletteNeeded)
				{
					BitmapPalette palette = bitmapSource.Palette;
					GdiImaging.ColorPalette gdiPalette = bitmap.Palette;
					IList<Color> colors = palette.Colors;
					for (int i = colors.Count - 1; i >= 0; --i)
					{
						Color color = colors[i];
						gdiPalette.Entries[i] = Gdi.Color.FromArgb(color.A, color.R, color.G, color.B);
					}
					bitmap.Palette = gdiPalette;
				}

				//複製解析度
				bitmap.SetResolution((float)bitmapSource.DpiX, (float)bitmapSource.DpiY);
			}
			catch
			{
				if (bitmap != null)
					bitmap.Dispose();
				return false;
			}

			//完成
			return true;
		}
        #endregion
		#region TryConvertToGdiPixelFormat
		/// <summary>
		/// 嘗試將指定的 System.Windows.Media.PixelFormat 轉換成對應的 System.Drawing.Imaging.PixelFormat 列舉常數。
		/// </summary>
		/// <param name="pixelFormat">指定的 System.Windows.Media.PixelFormat。</param>
		/// <param name="gdiPixelFormat">對應的 System.Drawing.Imaging.PixelFormat 列舉常數。</param>
		/// <returns>True 表示轉換成功，False 表示失敗。</returns>
		public static bool TryConvertToGdiPixelFormat(this PixelFormat pixelFormat, out GdiImaging.PixelFormat gdiPixelFormat)
		{
			if (pixelFormat == PixelFormats.Bgr24)
				gdiPixelFormat = GdiImaging.PixelFormat.Format24bppRgb;
			else if (pixelFormat == PixelFormats.Bgr32)
				gdiPixelFormat = GdiImaging.PixelFormat.Format32bppRgb;
			else if (pixelFormat == PixelFormats.Bgra32)
				gdiPixelFormat = GdiImaging.PixelFormat.Format32bppArgb;
			else if (pixelFormat == PixelFormats.Bgr565)
				gdiPixelFormat = GdiImaging.PixelFormat.Format16bppRgb565;
			else if (pixelFormat == PixelFormats.Rgb48)
				gdiPixelFormat = GdiImaging.PixelFormat.Format48bppRgb;
			else if (pixelFormat == PixelFormats.Rgba64)
				gdiPixelFormat = GdiImaging.PixelFormat.Format64bppArgb;
			else if (pixelFormat == PixelFormats.Indexed1)
				gdiPixelFormat = GdiImaging.PixelFormat.Format1bppIndexed;
			else if (pixelFormat == PixelFormats.Indexed4)
				gdiPixelFormat = GdiImaging.PixelFormat.Format4bppIndexed;
			else if (pixelFormat == PixelFormats.Indexed8)
				gdiPixelFormat = GdiImaging.PixelFormat.Format8bppIndexed;
			else if (pixelFormat == PixelFormats.Gray16)
				gdiPixelFormat = GdiImaging.PixelFormat.Format16bppGrayScale;
			else
			{
				gdiPixelFormat = GdiImaging.PixelFormat.Undefined;
				return false;
			}
			return true;
		}
        #endregion
		#region TryConvertToPixelFormat
		/// <summary>
		/// 嘗試將指定的 System.Drawing.Imaging.PixelFormat 列舉常數轉換成對應的 System.Windows.Media.PixelFormat。
		/// </summary>
		/// <param name="gdiPixelFormat">指定的 System.Drawing.Imaging.PixelFormat 列舉常數。</param>
		/// <param name="pixelFormat">對應的 System.Windows.Media.PixelFormat。</param>
		/// <returns>True 表示轉換成功，False 表示失敗。</returns>
		public static bool TryConvertToPixelFormat(this GdiImaging.PixelFormat gdiPixelFormat, out PixelFormat pixelFormat)
		{
			switch (gdiPixelFormat)
			{
				case GdiImaging.PixelFormat.Format24bppRgb:
					pixelFormat = PixelFormats.Bgr24;
					return true;
				case GdiImaging.PixelFormat.Format32bppArgb:
					pixelFormat = PixelFormats.Bgra32;
					return true;
				case GdiImaging.PixelFormat.Format32bppRgb:
					pixelFormat = PixelFormats.Bgr32;
					return true;
				case GdiImaging.PixelFormat.Format48bppRgb:
					pixelFormat = PixelFormats.Rgb48;
					return true;
				case GdiImaging.PixelFormat.Format64bppArgb:
					pixelFormat = PixelFormats.Rgba64;
					return true;
				case GdiImaging.PixelFormat.Format16bppRgb565:
					pixelFormat = PixelFormats.Bgr565;
					return true;
				case GdiImaging.PixelFormat.Format1bppIndexed:
					pixelFormat = PixelFormats.Indexed1;
					return true;
				case GdiImaging.PixelFormat.Format4bppIndexed:
					pixelFormat = PixelFormats.Indexed4;
					return true;
				case GdiImaging.PixelFormat.Format8bppIndexed:
					pixelFormat = PixelFormats.Indexed8;
					return true;
				case GdiImaging.PixelFormat.Format16bppGrayScale:
					pixelFormat = PixelFormats.Gray16;
					return true;
				default:
					pixelFormat = PixelFormats.Default;
					return false;
			}
		}
        #endregion
		#region WritePixels
		/// <summary>
		/// 將像素資料寫入指定的點陣圖中。
		/// </summary>
		/// <param name="bitmap">指定的點陣圖。</param>
		/// <param name="pixelFormat">像素格式。</param>
		/// <param name="palette">像素格式所需的調色盤。</param>
		/// <param name="buffer">像素資料。</param>
		/// <exception cref="ArgumentNullException">bitmap 或 buffer 為 Null (Visual Basic 為 Nothing)。</exception>
		public static void WritePixels(this IBitmapImage bitmap, PixelFormat pixelFormat, BitmapPalette palette, Array buffer)
		{
			WritePixels(bitmap, Int32Rect.Empty, pixelFormat, palette, buffer);
		}
		/// <summary>
		/// 將像素資料寫入指定的點陣圖中。
		/// </summary>
		/// <param name="bitmap">指定的點陣圖。</param>
		/// <param name="rect">要寫入的矩形範圍。</param>
		/// <param name="pixelFormat">像素格式。</param>
		/// <param name="palette">像素格式所需的調色盤。</param>
		/// <param name="buffer">像素資料。</param>
		/// <exception cref="ArgumentNullException">bitmap 或 buffer 為 Null (Visual Basic 為 Nothing)。</exception>
		public static void WritePixels(this IBitmapImage bitmap, Int32Rect rect, PixelFormat pixelFormat, BitmapPalette palette, Array buffer)
		{
			//確認
			if (buffer == null)
				throw new ArgumentNullException("buffer");

			//寫入像素資料
			GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
			try
			{
				WritePixels(bitmap, rect, pixelFormat, palette, handle.AddrOfPinnedObject());
			}
			finally
			{
				handle.Free();
			}
		}
		/// <summary>
		/// 將像素資料寫入指定的點陣圖中。
		/// </summary>
		/// <param name="bitmap">指定的點陣圖。</param>
		/// <param name="rect">要寫入的矩形範圍。</param>
		/// <param name="pixelFormat">像素格式。</param>
		/// <param name="palette">像素格式所需的調色盤。</param>
		/// <param name="buffer">像素資料緩衝區的指標。</param>
		/// <exception cref="ArgumentNullException">bitmap 為 Null (Visual Basic 為 Nothing)。</exception>
		public static void WritePixels(this IBitmapImage bitmap, Int32Rect rect, PixelFormat pixelFormat, BitmapPalette palette, IntPtr buffer)
		{
			//確認
			if (bitmap == null)
				throw new ArgumentNullException("bitmap");

			//取得複製大小
			if (rect == Int32Rect.Empty)
			{
				rect.Width = bitmap.PixelWidth;
				rect.Height = bitmap.PixelHeight;
			}

			//計算所需大小
			int stride = pixelFormat.BitsPerPixel * rect.Width / 8;
			int padding = 4 - (stride % 4);
			if (padding < 4)
				stride += padding;
			int bufferSize = (stride * rect.Height);

			//寫入像素資料
			bitmap.WritePixels(rect, pixelFormat, palette, buffer, bufferSize, stride);
		}
		#endregion
	}
	#region AccessPixelBufferCallback
	/// <summary>
	/// 提供存取點陣圖像素緩衝區時的回呼方法。
	/// </summary>
	/// <param name="pixelBuffer">像素緩衝區的記憶體位址。</param>
	/// <param name="width">像素寬度。</param>
	/// <param name="height">像素高度。</param>
	/// <param name="stride">掃描線的位元組長度，或稱為步距。</param>
	/// <param name="pixelFormat">像素格式。</param>
	/// <param name="palette">調色盤。</param>
	/// <param name="modified">是否有變更緩衝區內的像素資料。</param>
	public delegate void AccessPixelBufferCallback(IntPtr pixelBuffer, int width, int height, int stride, PixelFormat pixelFormat, BitmapPalette palette, ref bool modified);
	#endregion
	#region EnumerateArgbCallback
	/// <summary>
	/// 提供列舉 ARGB 時所回呼的方法。
	/// </summary>
	/// <param name="x">目前列舉位置的 X 座標。</param>
	/// <param name="y">目前列舉位置的 Y 座標。</param>
	/// <param name="alpha">目前列舉位置的 Alpha 值。</param>
	/// <param name="red">目前列舉位置的紅色值。</param>
	/// <param name="green">目前列舉位置的綠色值。</param>
	/// <param name="blue">目前列舉位置的藍色值。</param>
	/// <returns>True 表示繼續列舉下一個像素的 ARGB，False 表示中止列舉。</returns>
	public delegate bool EnumerateArgbCallback(int x, int y, int alpha, int red, int green, int blue);
	#endregion
}
